package com.koron.common.core.business.datadict.service;

import cn.hutool.core.util.ObjectUtil;
import com.koron.bean.base.Response;
import com.koron.bean.util.RedisUtils;
import com.koron.common.core.business.datadict.bean.po.SysDataDict;
import com.koron.common.core.business.datadict.bean.po.SysDataDictDetail;
import com.koron.common.core.business.datadict.mapper.SysDataDictDetailMapper;
import com.koron.common.core.util.CodeTools;
import com.koron.common.core.util.UpdateRedis;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 系统管理-数据字典详情{@code SysDataDictDetail}服务实现类
 *
 * <p>方法1-checkBeforeInsert：新增单条数据</p>
 * <p>方法2-deleteById：通过主键删除数据</p>
 * <p>方法3-update：修改数据</p>
 * <p>方法4-getDictionaryAndDictionaryDetails：查询所有的数据字典，及其关联的数据字典详情</p>
 * <p>方法5-getDetailsByDictionaryAndAppId：根据数据字典和所属租户查找对应的数据字典详情信息</p>
 * <p>方法6-getByClassifyIdAndCodeAndAppidAndKey：据classifyId，code，appid，key，来查询对应的数据</p>
 * <p>方法7-getByDictionary：通过所属字典ID查出的所有字典详情数据</p>
 * <p>方法8-getRedisKeyByDataDictDetail：根据sysDataDictDetail获取redisKey</p>
 *
 *
 *
 * @author 朱超
 * @since 2021-08-27
 */
@Service
public class SysDataDictDetailService {

    @Autowired
    private UpdateRedis updateRedis;

    @Autowired
    private SysDataDictService sysDataDictService;

    @Autowired
    private SysDataDictClassifyService sysDataDictClassifyService;

    private static final String key_prefix = "eam:dataDict:";

    /**
     * 新增单条数据
     *
     * @param sysDataDictDetail 实例请求
     * @param factory
     * @throws {@code Internal Server Error} 同一字典，同一租户下key不能重复
     * @throws {@code Internal Server Error} 同一字典，同一租户下value不能重复
     * @return Response对象
     * @see Response
     * @version 1.0
     */
    @TaskAnnotation("checkBeforeInsert")
    public Response checkBeforeInsert(SessionFactory factory, SysDataDictDetail sysDataDictDetail) {
        SysDataDictDetailMapper sysDataDictDetailMapper = factory.getMapper(SysDataDictDetailMapper.class);
        String dictionary = sysDataDictDetail.getDictionary();
        String appid = sysDataDictDetail.getAppid();
        String key = sysDataDictDetail.getKey();
        String value = sysDataDictDetail.getValue();

        // 1. 判断同一字典，同一租户下的key是否重复
        SysDataDictDetail uniqueKey = sysDataDictDetailMapper.getByDictionaryAndAppidAndKey(dictionary, appid, key);
        if (uniqueKey != null) {
            return Response.fail("同一字典，同一租户下key不能重复");
        }
        // 2. 判断同一字典，同一租户下的value是否重复
        /*SysDataDictDetail uniqueValue = sysDataDictDetailMapper.getByDictionaryAndAppidAndValue(dictionary, appid, value);
        if (uniqueValue != null) {
            return Response.fail("同一字典，同一租户下value不能重复");
        }*/
        // 3. 设置id
        sysDataDictDetail.setId(CodeTools.getCode32());
        // 4.插入数据
        sysDataDictDetailMapper.insert(sysDataDictDetail);
        // 5. redis更新
        updateRedis.setDataDictDetailInRedis(factory,sysDataDictDetail);
        // 6. redis更新数据字典
        SysDataDict sysDataDict = sysDataDictService.getById(factory,dictionary);
        List<SysDataDictDetail> sysDataDictDetailList = this.getByDictionary(factory, dictionary);
        sysDataDict.setSysDataDictDetailList(sysDataDictDetailList);
        updateRedis.setDataDictInRedis(sysDataDict);

        return Response.success(sysDataDictDetail);
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @param factory
     * @return Response对象
     * @see Response
     * @version 1.0
     */
    @TaskAnnotation("deleteById")
    public Response deleteById(SessionFactory factory, String id) {
        SysDataDictDetailMapper sysDataDictDetailMapper = factory.getMapper(SysDataDictDetailMapper.class);

        // 1. 根据id查出对应的数据
        SysDataDictDetail sysDataDictDetail = sysDataDictDetailMapper.getById(id);
        String dictionary = sysDataDictDetail.getDictionary();
        // 2. 获取redisKey
        String redisKey = getRedisKeyByDataDictDetail(factory,sysDataDictDetail);
        // 3. 数据库删除数据
        sysDataDictDetailMapper.deleteById(id);
        // 4. redis删除数据
        RedisUtils.delete(redisKey);
        // 5. redis更新数据字典
        SysDataDict sysDataDict = sysDataDictService.getById(factory,dictionary);
        List<SysDataDictDetail> sysDataDictDetailList = this.getByDictionary(factory, dictionary);
        sysDataDict.setSysDataDictDetailList(sysDataDictDetailList);
        updateRedis.setDataDictInRedis(sysDataDict);

        return Response.success("删除成功");
    }

    /**
     * 修改数据
     *
     * @param sysDataDictDetail
     * @param factory
     * @throws {@code Internal Server Error} 同一字典下的字典详情，key/value都不能相同
     * @return Response对象
     * @see Response
     * @version 1.0
     */
    @TaskAnnotation("checkBeforeUpdate")
    public Response checkBeforeUpdate(SessionFactory factory, SysDataDictDetail sysDataDictDetail) {
        SysDataDictDetailMapper sysDataDictDetailMapper = factory.getMapper(SysDataDictDetailMapper.class);
        String id = sysDataDictDetail.getId();
        String key = sysDataDictDetail.getKey();
        String value = sysDataDictDetail.getValue();
        String dictionary = sysDataDictDetail.getDictionary();
        String appid = sysDataDictDetail.getAppid();

        // 1. 同一字典,同一租户下的字典详情，key/value都不能相同
        List<SysDataDictDetail> sysDataDictDetails = sysDataDictDetailMapper.getDetailsByDictionaryAndAppId(dictionary,appid);
        for (SysDataDictDetail dataDictDetail : sysDataDictDetails) {
            // 20210720-朱超： 将数据详情本身的数据排除对比。
            if (!dataDictDetail.getId().equals(id)) {
                if (dataDictDetail.getKey().equals(key) || dataDictDetail.getValue().equals(value)) {
                    return Response.fail("同一字典下的字典详情，key/value都不能相同");
                }
            }
        }
        // 2. 通过了前面的判断，说明可以更新...如果更新了key，因为redisKey的生成规则，需要把redis中原来的数据删除
        SysDataDictDetail formerDataDictDetail = sysDataDictDetailMapper.getById(id);
        // 2.1 只有当key变更的时候也，redisKey才会变更
        if (!formerDataDictDetail.getKey().equals(key)) {
            // 2.2 获取原来的redisKey，并删除
            String formerRedisKey = getRedisKeyByDataDictDetail(factory, formerDataDictDetail);
            RedisUtils.delete(formerRedisKey);
        }
        // 3. 更新数据库
        sysDataDictDetailMapper.update(sysDataDictDetail);
        // 4. 更新redis
        updateRedis.setDataDictDetailInRedis(factory,sysDataDictDetail);
        // 5. redis更新数据字典
        SysDataDict sysDataDict = sysDataDictService.getById(factory,dictionary);
        List<SysDataDictDetail> sysDataDictDetailList = this.getByDictionary(factory, dictionary);
        sysDataDict.setSysDataDictDetailList(sysDataDictDetailList);
        updateRedis.setDataDictInRedis(sysDataDict);

        return Response.success("更新成功");
    }

    /**
     * 查询所有的数据字典，及其关联的数据字典详情
     *
     * @param factory
     * @return Response对象
     * @see Response
     * @version 1.0
     */
    @TaskAnnotation("getDictionaryAndDictionaryDetails")
    public Response getDictionaryAndDictionaryDetails(SessionFactory factory) {
        SysDataDictDetailMapper sysDataDictDetailMapper = factory.getMapper(SysDataDictDetailMapper.class);
        // 1. 先查出所有的数据字典
        List<SysDataDict> sysDataDictList = sysDataDictService.queryAll(factory, null);
        // 2. 再查出所有的数据详情
        List<SysDataDictDetail> sysDataDictDetailList = sysDataDictDetailMapper.getAll();
        // 3. 根据dictionary字段进行聚合
        Map<String,List<SysDataDictDetail>> map= sysDataDictDetailList.stream().collect(Collectors.groupingBy(SysDataDictDetail::getDictionary));
        // 4. 将对应的数据进行处理
        for (SysDataDict sysDataDict: sysDataDictList){
            List<SysDataDictDetail> sysDataDictDetails = map.get(sysDataDict.getId());
            if (ObjectUtil.isNull(sysDataDictDetails)) {
                continue;
            }
//            List<HashMap<String, Object>> maplist = new ArrayList<>();
//            for (SysDataDictDetail sysDataDictDetail : sysDataDictDetails) {
//                HashMap<String, Object> detailmap = Convert.convert(HashMap.class, sysDataDictDetail);
//                String lang = sysDataDictDetail.getLang();
//                if (StrUtil.isNotBlank(lang)) {
//                    HashMap<String, Object> langmap = FastJsonUtils.getJsonToBean(lang, HashMap.class);
//                    for (String key : langmap.keySet()) {
//                        detailmap.put(key, langmap.get(key));
//                    }
//                }
//                detailmap.remove("lang");
//                sysDataDictDetail.setLang(null);
//                maplist.add(detailmap);
//            }
            sysDataDict.setSysDataDictDetailList(sysDataDictDetails);
//            sysDataDict.setSysDataDictDetailmapList(maplist);
        }
        return Response.success(sysDataDictList);
    }


    /**
     * 根据数据字典和所属租户查找对应的数据字典详情信息
     *
     * @param dictionary 数据字典id
     * @param appid 租户id
     * @param factory
     * @return Response对象
     * @see Response
     * @version 1.0
     */
    @TaskAnnotation("getDetailsByDictionaryAndAppId")
    public Response getDetailsByDictionaryAndAppId(SessionFactory factory, String dictionary, String appid) {
        SysDataDictDetailMapper sysDataDictDetailMapper = factory.getMapper(SysDataDictDetailMapper.class);
        List<SysDataDictDetail> result = sysDataDictDetailMapper.getDetailsByDictionaryAndAppId(dictionary, appid);
        return Response.success(result);
    }

    /**
     * 根据classifyId，code，appid，key，来查询对应的数据
     *
     * @param classifyId
     * @param code
     * @param appid
     * @param key
     * @param factory
     * @return SysDataDictDetail
     * @see SysDataDictDetail
     * @version 1.0
     */
    public SysDataDictDetail getByClassifyIdAndCodeAndAppidAndKey(SessionFactory factory, String classifyId, String code, String appid, String key) {
        SysDataDictDetailMapper sysDataDictDetailMapper = factory.getMapper(SysDataDictDetailMapper.class);
        SysDataDictDetail sysDataDictDetail = new SysDataDictDetail();

        // 1. 获取redisKey
        String redisKey = key_prefix + classifyId + ":" + code + ":" + appid + ":" + key;
        // 2. 尝试从redis中获取数据
        Map<Object,Object> redisValue = RedisUtils.hmget(redisKey);
        if (redisValue.size() > 0) {
            // 3. 将redis中获取的数据赋值到实例中
            sysDataDictDetail.setId((String) redisValue.get("id"));
            sysDataDictDetail.setDictionary((String) redisValue.get("dictionary"));
            sysDataDictDetail.setAppid((String) redisValue.get("appid"));
            sysDataDictDetail.setKey((String) redisValue.get("key"));
            sysDataDictDetail.setValue((String) redisValue.get("value"));
        } else {
            // 4. 如果redis没数据，则从数据库获取
            // 4.1 根据classifyId和code获取对应的数据字典
            SysDataDict sysDataDict = sysDataDictService.getByClassifyIdAndCode(factory,classifyId,code);
            // 4.2 通过数据字典id，appid，key获得对应的数据字典详情
            String dictionary = sysDataDict.getId();
            sysDataDictDetail = sysDataDictDetailMapper.getByDictionaryAndAppidAndKey(dictionary,appid,key);
            // 5. 更新redis
            updateRedis.setDataDictDetailInRedis(factory,sysDataDictDetail);
        }

        return sysDataDictDetail;
    }

    /**
     * 通过所属字典ID查出的所有字典详情数据
     *
     * @param factory
     * @param dictionary 数据字典id
     * @return List<SysDataDictDetail>：数据字典对应的数据字典详情
     * @version 1.0
     */
    public List<SysDataDictDetail> getByDictionary(SessionFactory factory, String dictionary) {
        SysDataDictDetailMapper sysDataDictDetailMapper = factory.getMapper(SysDataDictDetailMapper.class);
        return sysDataDictDetailMapper.getByDictionary(dictionary);
    }

    /** 根据sysDataDictDetail获取redisKey
     *
     * @param factory
     * @param sysDataDictDetail
     *
     * @return redisKey
     * @see SysDataDictDetail
     * @version 1.0
     */
    public String getRedisKeyByDataDictDetail(SessionFactory factory, SysDataDictDetail sysDataDictDetail) {
        String dictionary = sysDataDictDetail.getDictionary();
        String appid = sysDataDictDetail.getAppid();
        String key = sysDataDictDetail.getKey();

        // 1. 根据dictionary获取数据字典实例，主要是classifyId,code
        SysDataDict sysDataDict = sysDataDictService.getById(factory,dictionary);
        String classifyId = sysDataDict.getClassifyId();
        String code = sysDataDict.getCode();
        // 2. 获取redisKey
        String redisKey = key_prefix + classifyId + ":" + code + ":" + appid + ":" + key;

        return redisKey;
    }
}
